package com.gitee.wsl.config.pref


import com.gitee.wsl.config.AbstractConfigModel
import com.gitee.wsl.data.store.getPreferenceOrNull
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.internal.SynchronizedObject
import kotlinx.coroutines.internal.synchronized

import kotlin.reflect.KProperty

internal class StringSetPref(
    val default: () -> Set<String>,
    override val key: String?,
    private val commitByDefault: Boolean
) : AbstractStringSetPref() {

    private var stringSet: MutableSet<String>? = null
    private var lastUpdate: Long = 0L

    override operator fun getValue(
        thisRef: AbstractConfigModel,
        property: KProperty<*>
    ): MutableSet<String> {
        if (stringSet != null ) {
            return stringSet!!
        }
        val prefSet = thisRef.storeServer.getPreferenceOrNull<HashSet<String>>(preferenceKey)
        stringSet = PrefMutableSet(
            thisRef,
            prefSet ?: default.invoke().toMutableSet(),
            preferenceKey
        )
        //lastUpdate = SystemClock.uptimeMillis()
        return stringSet!!
    }

    @OptIn(InternalCoroutinesApi::class)
    internal inner class PrefMutableSet(
        val kotprefModel: AbstractConfigModel,
        val set: MutableSet<String>,
        val key: String
    ) : MutableSet<String> by set, SynchronizedObject() {

        init {
            addAll(set)
        }

        private var transactionData: MutableSet<String>? = null
            get() {
                field = field ?: set.toMutableSet()
                return field
            }

        internal fun syncTransaction() {
            synchronized(this) {
                transactionData?.let {
                    set.clear()
                    set.addAll(it)
                    transactionData = null
                }
            }
        }
        
        override fun add(element: String): Boolean {
            /*if (kotprefModel.kotprefInTransaction) {
                val result = transactionData!!.add(element)
                kotprefModel.kotprefEditor!!.putStringSet(key, this)
                return result
            }*/
            val result = set.add(element)
            kotprefModel.storeServer.putPreference(key, set)
            return result
        }


        override fun addAll(elements: Collection<String>): Boolean {
            /*if (kotprefModel.kotprefInTransaction) {
                val result = transactionData!!.addAll(elements)
                kotprefModel.kotprefEditor!!.putStringSet(key, this)
                return result
            }*/
            val result = set.addAll(elements)
            kotprefModel.storeServer.putPreference(key, set)
            return result
        }

        
        override fun remove(element: String): Boolean {
            /*if (kotprefModel.kotprefInTransaction) {
                val result = transactionData!!.remove(element)
                kotprefModel.kotprefEditor!!.putStringSet(key, this)
                return result
            }*/
            val result = set.remove(element)
            kotprefModel.storeServer.putPreference(key, set)
            return result
        }

        
        override fun removeAll(elements: Collection<String>): Boolean {
            /*if (kotprefModel.kotprefInTransaction) {
                val result = transactionData!!.removeAll(elements)
                kotprefModel.kotprefEditor!!.putStringSet(key, this)
                return result
            }*/
            val result = set.removeAll(elements)
            kotprefModel.storeServer.putPreference(key, set)
            return result
        }

        
        override fun retainAll(elements: Collection<String>): Boolean {
            /*if (kotprefModel.kotprefInTransaction) {
                val result = transactionData!!.retainAll(elements)
                kotprefModel.kotprefEditor!!.putStringSet(key, this)
                return result
            }*/
            val result = set.retainAll(elements)
            kotprefModel.storeServer.putPreference(key, set)
            return result
        }

        
        override fun clear() {
            /*if (kotprefModel.kotprefInTransaction) {
                val result = transactionData!!.clear()
                kotprefModel.kotprefEditor!!.putStringSet(key, this)
                return result
            }*/
            set.clear()
            kotprefModel.storeServer.putPreference(key, set)
        }

        override fun contains(element: String): Boolean {
            if (kotprefModel.kotprefInTransaction) {
                return element in transactionData!!
            }
            return element in set
        }

        override fun containsAll(elements: Collection<String>): Boolean {
            if (kotprefModel.kotprefInTransaction) {
                return transactionData!!.containsAll(elements)
            }
            return set.containsAll(elements)
        }

        override fun iterator(): MutableIterator<String> {
            /*return if (kotprefModel.kotprefInTransaction) {
                kotprefModel.kotprefEditor!!.putStringSet(key, this@PrefMutableSet)
                KotprefMutableIterator(transactionData!!.iterator(), true)
            } else {
                KotprefMutableIterator(set.iterator(), false)
            }*/

            return KotprefMutableIterator(set.iterator(), false)
        }

        override val size: Int
            get() {
                if (kotprefModel.kotprefInTransaction) {
                    return transactionData!!.size
                }
                return set.size
            }

        private inner class KotprefMutableIterator(
            val baseIterator: MutableIterator<String>,
            val inTransaction: Boolean
        ) : MutableIterator<String> by baseIterator {

            
            override fun remove() {
                baseIterator.remove()
                if (!inTransaction) {
                    kotprefModel.storeServer.putPreference(key, set)
                }
            }
        }
    }
}
